概述
Small是一个非常简洁的插件化框架,它的口号是做最轻巧的跨平台插件化框架。
Small 官方使用文档
Small Github源码地址
那么首先我们从官方给出的 Sample 中初步了解一下Small框架。
运行DevSample
从上面给出的Small Github源码地址中现在Small源码。
在 Small/Android/ 下面有两个目录:
- Sample/:使用者模式
- DevSample/:开发者模式
他们有什么区别呢?可以看他们编译后的结果:
Sample:
1 | | type | name | PP | sdk | aapt | support | file(armeabi) | size | |
DevSample:
1 | | type | name | PP | sdk | aapt | support | file | size | |
编译后的结果 Sample 是 .so,DevSample 是 .apk。
造成这样的区别原因是在开发者模式的 build.gradle 里面有下面的设置:
1 | small { |
buildToAssets
决定是否将插件作为 apk 文件打包到宿主 apk 的 assets 目录下。默认为 false,即作为 so 文件打包到宿主 apk 的 lib 目录下。
配套的,还需要在宿主的 Application
里指定读取插件的位置:
1 |
|
1 | if (Small.isLoadFromAssets()) { |
可以看到,BuildConfig.LOAD_FROM_ASSETS
为 true 时,从 /data/data/nativeLibraryDir
中读取 so 格式插件。
那么现在我们就导入 DevSample 工程。
导入DevSample工程
打开Android Studio,File->Open->Open File or Project… 选择DevSample文件夹然后打开。
如图:
DevSample 示例工程中有下面的模块:
- app 宿主工程
- app.* 应用插件,包含Activity/Fragment的插件
- lib.* 公共库插件
- web.* 本地网页插件
- app+* 宿主分身模块
- gradle-small Small中的一个gradle自定义插件,用于打包组件
出于业务需求考虑,Small定义了两类插件:公共库插件与应用插件。
应用插件相对简单,就是用来把大应用拆分成一个个小的业务单元。而公共库插件则是为这些业务单元提供公共的代码与资源,比如可以将在多个应用插件间可以复用的一些主题、界面边距资源提取出来作为一个公共库插件。
编译插件
在运行前必须要编译生成插件。
- 编译公共库插件:
指的是编译lib.*的插件。
1 | ./gradlew buildLib -q (-q是安静模式,可以让输出更好看,也可以不加) |
输出:
1 | Small building library 1 of 5 - app (0x7f) |
- 编译应用插件
指的是编译app.*的插件。
1 | ./gradlew buildBundle -q (-q是安静模式,可以让输出更好看,也可以不加) |
输出:
1 | Small building bundle 1 of 6 - app.detail (0x67) |
单独编译一个组件可以使用:
1 | ./gradlew -p app.main assembleRelease |
或者
1 | ./gradlew :app.main:assembleRelease |
编译后生成的文件在 Android/Sample/app/smallLibs 目录中。
- 检查编译情况
命令:
1 | ./gradlew small |
输出:
1 | :small |
运行
点击
运行需要的组件。
app.home 无法单独运行是因为它只包含一个 Fragment
,没有 Launcher Activity。
如果需要修改某个插件,修改完后重新编译该插件,在重新编译宿主工程就可以了。
清除插件
清除基础库:
1 | ./gradlew cleanLib -q |
清除所有插件:
1 | ./gradlew cleanBundle -q |
Small工程解析
插件路由
在宿主工程 app 的 assets 目录下面有个文件 bundle.json,它就想一个插件路由表一样,Small 中用它来对插件进行管理:
1 | { |
bundle.json 中的每一个元素都是对一个插件的声明。
- uri:跳转插件的界面都是通过uri来指定的,也就是一个uri唯一对应一个插件
- pkg:插件的包名
- type:插件类型:app应用插件;lib公共库插件
- rules:插件的子路由表
在加载插件时会根据type类型来寻找合适的 BundleLauncher
,如果这里没有指定type,那么就要根据包名来判断插件类型,比如包名里面要包含 app 、lib 或者 web 等。
主路由
在代码中通过:
1 | Small.openUri("detail", context); |
来通过包名来查找对应插件,调用该插件下面的 Launcher Activity。即 net.wequick.example.small.app.detail
下面的MainActivity
。
子路由
如果是:
1 | Small.openUri("detail/Sub", context); |
就会调用 net.wequick.example.small.app.detail
下面的 SubActivity
。
传递参数
在调用插件的时候还可以传递参数:
1 | Small.openUri("detail?from=app.home", context); |
在调起的插件app.detail/MainActivity
中通过下面方法来查询参数:
1 | Uri uri = Small.getUri(this); |